// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-11-20

package searched

import (
	"fmt"
	"html/template"
	"sort"
	"time"
)

// Trace
// 链路跟踪数据.
type Trace struct {
	CSS template.CSS `json:"css"`

	Nano         int64
	ItemTotal    int     `json:"item_total"`
	SpanList     []*Span `json:"span_list,omitempty" label:"跟踪列表"`
	SpanTotal    int     `json:"span_count"`
	TraceId      string  `json:"trace_id"`
	TracedId     string  `json:"traced_id"`
	SpanId       string  `json:"span_id"`
	ParentSpanId string  `json:"parent_span_id"`

	notSortedSpan []*Span
}

// NewTrace
// 创建跟踪结果.
func NewTrace() *Trace {
	return &Trace{
		Nano:          time.Now().UnixNano(),
		SpanList:      make([]*Span, 0),
		notSortedSpan: make([]*Span, 0),
	}
}

// Add
// 添加跟踪.
func (o *Trace) Add(span *Span) {
	// 1. 加入列表.
	o.notSortedSpan = append(o.notSortedSpan, span)

	// 2. 刷新数据.
	if o.TracedId == "" && span.TraceId != "" {
		o.TracedId = span.TraceId
	}
}

// Child
// 构建子级.
func (o *Trace) Child(mapper Mapper) {
	for _, span := range o.notSortedSpan {
		span.Child(mapper)
	}
}

// Sort
// 数据排序.
func (o *Trace) Sort() *Trace {
	var (
		index = make(map[string]*Span)
		key   string
		keys  = make([]string, 0)
	)

	// 1. 构建中间值.
	for i, span := range o.notSortedSpan {
		// 1.1 内部排序.
		span.Sort()

		// 1.2 中间处理.
		key = fmt.Sprintf(`%d-%04d`, span.StartTime, i)
		keys = append(keys, key)
		index[key] = span
	}

	// 2. 中间值排序.
	sort.Strings(keys)

	// 3. 按顺序添加.
	for _, key = range keys {
		if span, ok := index[key]; ok {
			o.SpanList = append(o.SpanList, span)
		}
	}

	// 4. 清理数据.
	o.notSortedSpan = nil
	return o
}

func (o *Trace) Update() *Trace {
	for _, span := range o.SpanList {
		span.Update()
	}
	return o
}
